#include "StdAfx.h"
#include "LitScriptModule.h"
#include "LitScriptEngine.h"
#include "LitScriptPreprocessor.h"

namespace Lit
{
	/*/////////////////////////////////////
				SCRIPT MODULE
	/////////////////////////////////////*/
	ScriptModule::ScriptModule(RefPtr<ScriptEngine> engine, const std::string &module_name, Flags flags)
		: mFlags( flags )
		, mEngine( engine )
		, mName( module_name )
		, mGlobalLine( 0 )
	{
		setDefaultPreprocessor( );
		mPreprocessor->setIncludeCallback(boost::bind(&ScriptModule::_include, this, _1));
		mPreprocessor->setDefineCallback(boost::bind(&ScriptModule::_define, this, _1, _2));
		mModule = engine->data()->GetModule( module_name.c_str(), (asEGMFlags)flags );
	}
		
	ScriptModule::ScriptModule(const ScriptModule& rhs)
		: mFlags( rhs.mFlags )
		, mModule( rhs.mModule )
		, mName( rhs.mName )
		, mGlobalLine( rhs.mGlobalLine )
		, mPreprocessor( rhs.mPreprocessor )
	{
	}

	ScriptModule::~ScriptModule(void)
	{
		mPreprocessor.destroy();
	}
	

	ScriptContextState ScriptModule::execute(const std::string &entry_point, RefPtr<ScriptContext> context)
	{
		ScriptFunctionPtr func = mModule->GetFunctionByDecl(entry_point.c_str());
		if( !func )
			throw ScriptNoEntryPoint(entry_point, EXC_LOC);
		int r = context->prepare( func );
		assert( r>=0 );
		return context->execute( );
	}

	std::string			ScriptModule::getName() const{ return mName; }
	ScriptModuleFlags	ScriptModule::getFlags() const{ return mFlags; }
	
	size_t numLines( const std::string &str )
	{
		std::stringstream ss(str);
		size_t ln=0;
		std::string lne;
		while( !ss.eof() )
		{
			std::getline(ss,lne);
			ln++;
		}
		return ln;
	}
	

	void ScriptModule::releasePreprocessor()
	{
		if( mPreprocessor ) mPreprocessor.destroy();
	}
	void ScriptModule::setPreprocessor( ScriptPreprocessorPtr proc )
	{
		if( !proc ) return;
		releasePreprocessor();
		mPreprocessor = proc;
	}
	void ScriptModule::setDefaultPreprocessor()
	{
		releasePreprocessor();
		mPreprocessor = new ScriptPreprocessor;
	}

	int					ScriptModule::addSection( const std::string &name, const std::string &content )
	{
		ScriptPreprocessor::Section sec( name, content, mGlobalLine );
		mPreprocessor->processScriptSection(  sec );
		std::string new_content = sec.join(ScriptPreprocessor::Win32Endl);
		int ret = mModule->AddScriptSection( name.c_str(), new_content.c_str(), new_content.size(), mGlobalLine );
		assert( ret >= 0 );
		mGlobalLine += sec.numLines();
		return ret;
	}
		
	bool ScriptModule::_include( const FilePath& path )
	{
		if( !hasInclude( path ) )
		{
			if( mEngine->isIncludableContent( path )  ){
				std::string p = mEngine->getIncludePath( path );
				mIncludes.addInclude(p);
				return true;
			}
		}
		return false;
	}
	void ScriptModule::_define( const std::string&name, const std::string &value ){
	}
	void ScriptModule::saveByteCode( ScriptByteStreamPtr strm )
	{
#ifndef NDEBUG
		mModule->SaveByteCode( *strm, false );
#else
		mModule->SaveByteCode( *strm, true );
#endif
		strm.destroy();
	}
	void ScriptModule::loadByteCode( ScriptByteStreamPtr strm )
	{
#ifndef NDEBUG
		mModule->LoadByteCode( *strm, false );
#else
		mModule->LoadByteCode( *strm, true );
#endif
		strm.destroy();
	}
	
	const RefPtr<ScriptEngine>& ScriptModule::getEngine() const{ return mEngine; }
	RefPtr<ScriptEngine>&		ScriptModule::getEngine(){ return mEngine; }
	
	const ScriptModule::Ptr&				ScriptModule::data() const{ return mModule; }
	ScriptModule::Ptr&					ScriptModule::data(){ return mModule; }

	int							ScriptModule::build(){ return mModule->Build(); }
};